package partFour;
/*需求：设计多线程编程模型，4个窗口共计售票100张
 * 本方案使用多线程编程方案2，实现Runnable接口的方式来完成*/
public class TestRunnablev2 {
    public static void main(String[] args) {
        //5.创建Runnable接口的实现类对象，作为目标业务对象
        TicketsRunnable2 target = new TicketsRunnable2();
        //6.创建多个Thread类线程对象，并将target业务交给多个线程对象来处理
        Thread t1 = new Thread(target);
        Thread t2 = new Thread(target);
        Thread t3 = new Thread(target);
        Thread t4 = new Thread(target);
        //7.以多线程的方式启动多个线程对象
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

//1.自定义多线程类实现Runnable接口
class TicketsRunnable2 implements Runnable {
    //3.定义一个成员变量，用来保存票数100
    //由于自定义类对象只创建了一次，所以票数被所有线程对象Thread共享
    //不需要添加static，只卖了100张票，不会卖400次*/
    int tickets = 100;
    Object o = new Object();

    //2.添加接口中未实现的方法，方法里是我们的业务
    @Override
    public void run() {
        //4.1循环卖票
        while (true) {
            //synchronized (TestRunnablev2.class) {//此方法也可以，只要保证唯一即可
            synchronized (o) {
                if (tickets > 0) {
                    //7.让每个线程经历休眠，增加线程状态切换频率与出错的概率
                    //问题1：产生重卖的现象，同一张票卖给多人
                    //问题2：产生了超卖的现象，超出了规定的票数100，出现了0，-1，-2
                    try {
                        Thread.sleep(10);//让当前线程休眠10ms
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //4.2打印当前正在售票的线程名称 & 票数-1
                    System.out.println(Thread.currentThread().getName() + "=" + tickets--);
                    //4.3设置死循环的出口，没票了就停止卖票
                    if (tickets <= 0) break;
                }
            }
        }
    }
}